home *** CD-ROM | disk | FTP | other *** search
/ Suzy B Software 2 / Suzy B Software CD-ROM 2 (1994).iso / new_file / mintprgs / mint112s / mint112s.lzh / dosdir.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-14  |  31.9 KB  |  1,424 lines

  1. /*
  2. Copyright 1990,1991,1992 Eric R. Smith.
  3. Copyright 1992,1993,1994 Atari Corporation.
  4. All rights reserved.
  5. */
  6.  
  7. /* DOS directory functions */
  8.  
  9. #include "mint.h"
  10.  
  11. extern int aliasdrv[];    /* in filesys.c */
  12.  
  13. /* change to a new drive: should always return a map of valid drives */
  14.  
  15. long ARGS_ON_STACK
  16. d_setdrv(d)
  17.     int d;
  18. {
  19.     long r;
  20.     extern long dosdrvs;    /* in filesys.c */
  21.  
  22.     r = drvmap() | dosdrvs | PSEUDODRVS;
  23.  
  24.     TRACE(("Dsetdrv(%d)", d));
  25.     if (d < 0 || d >= NUM_DRIVES || (r & (1L << d)) == 0) {
  26.         DEBUG(("Dsetdrv: invalid drive %d", d));
  27.         return r;
  28.     }
  29.  
  30.     curproc->base->p_defdrv = curproc->curdrv = d;
  31.     return r;
  32. }
  33.  
  34.  
  35. long ARGS_ON_STACK
  36. d_getdrv()
  37. {
  38.     TRACE(("Dgetdrv"));
  39.     return curproc->curdrv;
  40. }
  41.  
  42. long ARGS_ON_STACK
  43. d_free(buf, d)
  44.     long *buf;
  45.     int d;
  46. {
  47.     fcookie *dir = 0;
  48.     FILESYS *fs;
  49.     fcookie root;
  50.     long r;
  51.  
  52.     TRACE(("Dfree(%d)", d));
  53.  
  54. /* drive 0 means current drive, otherwise it's d-1 */
  55.     if (d)
  56.         d = d-1;
  57.     else
  58.         d = curproc->curdrv;
  59.  
  60. /* If it's not a standard drive or an alias of one, get the pointer to
  61.    the filesystem structure and use the root directory of the
  62.    drive. */
  63.     if (d < 0 || d >= NUM_DRIVES) {
  64.         int i;
  65.  
  66.         for (i = 0; i < NUM_DRIVES; i++) {
  67.             if (aliasdrv[i] == d) {
  68.                 d = i;
  69.                 goto aliased;
  70.             }
  71.         }
  72.  
  73.         fs = get_filesys (d);
  74.         if (!fs)
  75.           return EDRIVE;
  76.         r = fs->root (d, &root);
  77.         if (r < 0)
  78.           return r;
  79.         r = (*fs->dfree) (&root, buf);
  80.         release_cookie (&root);
  81.         return r;
  82.     }
  83.  
  84. /* check for a media change -- we don't care much either way, but it
  85.  * does keep the results more accurate
  86.  */
  87.     (void)disk_changed(d);
  88.  
  89. aliased:
  90.  
  91. /* use current directory, not root, since it's more likely that
  92.  * programs are interested in the latter (this makes U: work much
  93.  * better)
  94.  */
  95.     dir = &curproc->curdir[d];
  96.     if (!dir->fs) {
  97.         DEBUG(("Dfree: bad drive"));
  98.         return EDRIVE;
  99.     }
  100.  
  101.     return (*dir->fs->dfree)(dir, buf);
  102. }
  103.  
  104. long ARGS_ON_STACK
  105. d_create(path)
  106.     const char *path;
  107. {
  108.     fcookie dir;
  109.     long r;
  110.     char temp1[PATH_MAX];
  111.  
  112.     TRACE(("Dcreate(%s)", path));
  113.  
  114.     r = path2cookie(path, temp1, &dir);
  115.     if (r) {
  116.         DEBUG(("Dcreate(%s): returning %ld", path, r));
  117.         return r;    /* an error occured */
  118.     }
  119. /* check for write permission on the directory */
  120.     r = dir_access(&dir, S_IWOTH);
  121.     if (r) {
  122.         DEBUG(("Dcreate(%s): write access to directory denied",path));
  123.         release_cookie(&dir);
  124.         return r;
  125.     }
  126.     r = (*dir.fs->mkdir)(&dir, temp1, DEFAULT_DIRMODE & ~curproc->umask);
  127.     release_cookie(&dir);
  128.     return r;
  129. }
  130.  
  131. long ARGS_ON_STACK
  132. d_delete(path)
  133.     const char *path;
  134. {
  135.     fcookie parentdir, targdir;
  136.     long r;
  137.     PROC *p;
  138.     int i;
  139.     XATTR xattr;
  140.     char temp1[PATH_MAX];
  141.  
  142.     TRACE(("Ddelete(%s)", path));
  143.  
  144.     r = path2cookie(path, temp1, &parentdir);
  145.  
  146.     if (r) {
  147.         DEBUG(("Ddelete(%s): error %lx", path, r));
  148.         release_cookie(&parentdir);
  149.         return r;
  150.     }
  151. /* check for write permission on the directory which the target
  152.  * is located
  153.  */
  154.     if ((r = dir_access(&parentdir, S_IWOTH)) != 0) {
  155.         DEBUG(("Ddelete(%s): access to directory denied", path));
  156.         release_cookie(&parentdir);
  157.         return r;
  158.     }
  159.  
  160. /* now get the info on the file itself */
  161.  
  162.     r = relpath2cookie(&parentdir, temp1, NULL, &targdir, 0);
  163.     if (r) {
  164. bailout:
  165.         release_cookie(&parentdir);
  166.         DEBUG(("Ddelete: error %ld on %s", r, path));
  167.         return r;
  168.     }
  169.     if ((r = (*targdir.fs->getxattr)(&targdir, &xattr)) != 0) {
  170.         release_cookie(&targdir);
  171.         goto bailout;
  172.     }
  173.  
  174. /* if the "directory" is a symbolic link, really unlink it */
  175.     if ( (xattr.mode & S_IFMT) == S_IFLNK ) {
  176.         r = (*parentdir.fs->remove)(&parentdir, temp1);
  177.     } else if ( (xattr.mode & S_IFMT) != S_IFDIR ) {
  178.         DEBUG(("Ddelete: %s is not a directory", path));
  179.         r = EPTHNF;
  180.     } else {
  181.  
  182. /* don't delete anyone else's root or current directory */
  183.         for (p = proclist; p; p = p->gl_next) {
  184.         if (p->wait_q == ZOMBIE_Q || p->wait_q == TSR_Q)
  185.             continue;
  186.         for (i = 0; i < NUM_DRIVES; i++) {
  187.             if (samefile(&targdir, &p->root[i])) {
  188.                 DEBUG(("Ddelete: directory %s is a root directory",
  189.                     path));
  190. noaccess:
  191.                 release_cookie(&targdir);
  192.                 release_cookie(&parentdir);
  193.                 return EACCDN;
  194.             } else if (samefile(&targdir, &p->curdir[i])) {
  195.                 if (i == p->curdrv && p != curproc) {
  196.                     DEBUG(("Ddelete: directory %s is in use",
  197.                         path));
  198.                     goto noaccess;
  199.                 } else {
  200.                     release_cookie(&p->curdir[i]);
  201.                     dup_cookie(&p->curdir[i], &p->root[i]);
  202.                 } 
  203.             }
  204.         }
  205.         }
  206.         release_cookie(&targdir);
  207.         r = (*parentdir.fs->rmdir)(&parentdir, temp1);
  208.     }
  209.     release_cookie(&parentdir);
  210.     return r;
  211. }
  212.  
  213. long ARGS_ON_STACK
  214. d_setpath(path)
  215.     const char *path;
  216. {
  217.     fcookie dir;
  218.     int drv = curproc->curdrv;
  219.     int i;
  220.     char c;
  221.     long r;
  222.     XATTR xattr;
  223.  
  224.     TRACE(("Dsetpath(%s)", path));
  225.  
  226.     r = path2cookie(path, follow_links, &dir);
  227.  
  228.     if (r) {
  229.         DEBUG(("Dsetpath(%s): returning %ld", path, r));
  230.         return r;
  231.     }
  232.  
  233.     if (path[0] && path[1] == ':') {
  234.         c = *path;
  235.         if (c >= 'a' && c <= 'z')
  236.             drv = c-'a';
  237.         else if (c >= 'A' && c <= 'Z')
  238.             drv = c-'A';
  239.     }
  240.  
  241.     r = (*dir.fs->getxattr)(&dir, &xattr);
  242.  
  243.     if (r < 0) {
  244.         DEBUG(("Dsetpath: file '%s': attributes not found", path));
  245.         release_cookie(&dir);
  246.         return r;
  247.     }
  248.  
  249.     if (!(xattr.attr & FA_DIR)) {
  250.         DEBUG(("Dsetpath(%s): not a directory",path));
  251.         release_cookie(&dir);
  252.         return EPTHNF;
  253.     }
  254.  
  255.     if (denyaccess(&xattr, S_IROTH|S_IXOTH)) {
  256.         DEBUG(("Dsetpath(%s): access denied", path));
  257.         release_cookie(&dir);
  258.         return EACCDN;
  259.     }
  260. /*
  261.  * watch out for symbolic links; if c:\foo is a link to d:\bar, then
  262.  * "cd c:\foo" should also change the drive to d:
  263.  */
  264.     if (drv != UNIDRV && dir.dev != curproc->root[drv].dev) {
  265.         for (i = 0; i < NUM_DRIVES; i++) {
  266.             if (curproc->root[i].dev == dir.dev &&
  267.                 curproc->root[i].fs == dir.fs) {
  268.                 if (drv == curproc->curdrv)
  269.                     curproc->curdrv = i;
  270.                 drv = i;
  271.                 break;
  272.             }
  273.         }
  274.     }
  275.     release_cookie(&curproc->curdir[drv]);
  276.     curproc->curdir[drv] = dir;
  277.     return 0;
  278. }
  279.  
  280. /* jr: like d_getpath, except that the caller provides a limit
  281.    for the max. number of characters to be put into the buffer.
  282.    Inspired by POSIX.1, getcwd(), 5.2.2 */
  283.  
  284. long ARGS_ON_STACK
  285. d_getcwd(path, drv, size)
  286.     char *path;
  287.     int drv, size;
  288. {
  289.     fcookie *dir, *root;
  290.     long r;
  291.     char buf[PATH_MAX];
  292.     FILESYS *fs;
  293.  
  294.     TRACE(("Dgetcwd(%c, %d)", drv + '@', size));
  295.     if (drv < 0 || drv > NUM_DRIVES)
  296.         return EDRIVE;
  297.  
  298.     drv = (drv == 0) ? curproc->curdrv : drv-1;
  299.  
  300.     root = &curproc->root[drv];
  301.  
  302.     if (!root->fs) {    /* maybe not initialized yet? */
  303.         changedrv(drv);
  304.         root = &curproc->curdir[drv];
  305.         if (!root->fs)
  306.             return EDRIVE;
  307.     }
  308.     fs = root->fs;
  309.     dir = &curproc->curdir[drv];
  310.  
  311.     if (!(fs->fsflags & FS_LONGPATH)) {
  312.         r = (*fs->getname)(root, dir, buf, PATH_MAX);
  313.         if (r) return r;
  314.         if (strlen(buf) < size) {
  315.             strcpy(path, buf);
  316.             return 0;
  317.         } else {
  318.             return ERANGE;
  319.         }
  320.     }
  321.     return (*fs->getname)(root, dir, path, size);
  322. }
  323.  
  324. long ARGS_ON_STACK
  325. d_getpath(path, drv)
  326.     char *path;
  327.     int drv;
  328. {
  329.     TRACE(("Dgetpath(%c)", drv + '@'));
  330.     return d_getcwd(path, drv, PATH_MAX);
  331. }
  332.  
  333. long ARGS_ON_STACK
  334. f_setdta(dta)
  335.     DTABUF *dta;
  336. {
  337.  
  338.     TRACE(("Fsetdta: %lx", dta));
  339.     curproc->dta = dta;
  340.     curproc->base->p_dta = (char *)dta;
  341.     return 0;
  342. }
  343.  
  344. long ARGS_ON_STACK
  345. f_getdta()
  346. {
  347.     long r;
  348.  
  349.     r = (long)curproc->dta;
  350.     TRACE(("Fgetdta: returning %lx", r));
  351.     return r;
  352. }
  353.  
  354. /*
  355.  * Fsfirst/next are actually implemented in terms of opendir/readdir/closedir.
  356.  */
  357.  
  358. long ARGS_ON_STACK
  359. f_sfirst(path, attrib)
  360.     const char *path;
  361.     int attrib;
  362. {
  363.     char *s, *slash;
  364.     FILESYS *fs;
  365.     fcookie dir, newdir;
  366.     DTABUF *dta;
  367.     DIR *dirh;
  368.     XATTR xattr;
  369.     long r;
  370.     int i, havelabel;
  371.     char temp1[PATH_MAX];
  372.  
  373.     TRACE(("Fsfirst(%s, %x)", path, attrib));
  374.  
  375.     r = path2cookie(path, temp1, &dir);
  376.  
  377.     if (r) {
  378.         DEBUG(("Fsfirst(%s): path2cookie returned %ld", path, r));
  379.         return r;
  380.     }
  381.  
  382. /*
  383.  * we need to split the last name (which may be a pattern) off from
  384.  * the rest of the path, even if FS_KNOPARSE is true
  385.  */
  386.     slash = 0;
  387.     s = temp1;
  388.     while (*s) {
  389.         if (*s == '\\')
  390.             slash = s;
  391.         s++;
  392.     }
  393.  
  394.     if (slash) {
  395.         *slash++ = 0;    /* slash now points to a name or pattern */
  396.         r = relpath2cookie(&dir, temp1, follow_links, &newdir, 0);
  397.         release_cookie(&dir);
  398.         if (r) {
  399.             DEBUG(("Fsfirst(%s): lookup returned %ld", path, r));
  400.             return r;
  401.         }
  402.         dir = newdir;
  403.     } else {
  404.         slash = temp1;
  405.     }
  406.  
  407. /* BUG? what if there really is an empty file name? */
  408.     if (!*slash) {
  409.         DEBUG(("Fsfirst: empty pattern"));
  410.         return EFILNF;
  411.     }
  412.  
  413.     fs = dir.fs;
  414.     dta = curproc->dta;
  415.  
  416. /* Now, see if we can find a DIR slot for the search. We use the following
  417.  * heuristics to try to avoid destroying a slot:
  418.  * (1) if the search doesn't use wildcards, don't bother with a slot
  419.  * (2) if an existing slot was for the same DTA address, re-use it
  420.  * (3) if there's a free slot, re-use it. Slots are freed when the
  421.  *     corresponding search is terminated.
  422.  */
  423.  
  424.     for (i = 0; i < NUM_SEARCH; i++) {
  425.         if (curproc->srchdta[i] == dta) {
  426.             dirh = &curproc->srchdir[i];
  427.             if (dirh->fc.fs) {
  428.                 (*dirh->fc.fs->closedir)(dirh);
  429.                 release_cookie(&dirh->fc);
  430.                 dirh->fc.fs = 0;
  431.             }
  432.             curproc->srchdta[i] = 0; /* slot is now free */
  433.         }
  434.     }
  435.  
  436. /* copy the pattern over into dta_pat into TOS 8.3 form */
  437. /* remember that "slash" now points at the pattern (it follows the last \,
  438.    if any)
  439.  */
  440.     copy8_3(dta->dta_pat, slash);
  441.  
  442. /* if attrib & FA_LABEL, read the volume label */
  443. /* BUG: the label date and time are wrong. Does it matter?
  444.  */
  445.     havelabel = 0;
  446.     if (attrib & FA_LABEL) {
  447.         r = (*fs->readlabel)(&dir, dta->dta_name, TOS_NAMELEN+1);
  448.         dta->dta_attrib = FA_LABEL;
  449.         dta->dta_time = dta->dta_date = 0;
  450.         dta->dta_size = 0;
  451.         dta->magic = EVALID;
  452.         if (r == 0 && !pat_match(dta->dta_name, dta->dta_pat))
  453.             r = EFILNF;
  454.         if (attrib == FA_LABEL)
  455.             return r;
  456.         else if (r == 0)
  457.             havelabel = 1;
  458.     }
  459.  
  460.     if (!havelabel && has_wild(slash) == 0) { /* no wild cards in pattern */
  461.         r = relpath2cookie(&dir, slash, follow_links, &newdir, 0);
  462.         if (r == 0) {
  463.             r = (*newdir.fs->getxattr)(&newdir, &xattr);
  464.             release_cookie(&newdir);
  465.         }
  466.         release_cookie(&dir);
  467.         if (r) {
  468.             DEBUG(("Fsfirst(%s): couldn't get file attributes",path));
  469.             return r;
  470.         }
  471.         dta->magic = EVALID;
  472.         dta->dta_attrib = xattr.attr;
  473.         dta->dta_time = xattr.mtime;
  474.         dta->dta_date = xattr.mdate;
  475.         dta->dta_size = xattr.size;
  476.         strncpy(dta->dta_name, slash, TOS_NAMELEN-1);
  477.         dta->dta_name[TOS_NAMELEN-1] = 0;
  478.         if (curproc->domain == DOM_TOS &&
  479.             !(fs->fsflags & FS_CASESENSITIVE))
  480.             strupr(dta->dta_name);
  481.         return 0;
  482.     }
  483.  
  484. /* There is a wild card. Try to find a slot for an opendir/readdir
  485.  * search. NOTE: we also come here if we were asked to search for
  486.  * volume labels and found one.
  487.  */
  488.     for (i = 0; i < NUM_SEARCH; i++) {
  489.         if (curproc->srchdta[i] == 0)
  490.             break;
  491.     }
  492.     if (i == NUM_SEARCH) {
  493.         int oldest = 0; long oldtime = curproc->srchtim[0];
  494.  
  495.         DEBUG(("Fsfirst(%s): having to re-use a directory slot!",path));
  496.         for (i = 1; i < NUM_SEARCH; i++) {
  497.             if (curproc->srchtim[i] < oldtime) {
  498.                 oldest = i;
  499.                 oldtime = curproc->srchtim[i];
  500.             }
  501.         }
  502.     /* OK, close this directory for re-use */
  503.         i = oldest;
  504.         dirh = &curproc->srchdir[i];
  505.         if (dirh->fc.fs) {
  506.             (*dirh->fc.fs->closedir)(dirh);
  507.             release_cookie(&dirh->fc);
  508.             dirh->fc.fs = 0;
  509.         }
  510.         curproc->srchdta[i] = 0;
  511.     }
  512.  
  513. /* check to see if we have read permission on the directory (and make
  514.  * sure that it really is a directory!)
  515.  */
  516.     r = dir_access(&dir, S_IROTH);
  517.     if (r) {
  518.         DEBUG(("Fsfirst(%s): access to directory denied (error code %ld)", path, r));
  519.         release_cookie(&dir);
  520.         return r;
  521.     }
  522.  
  523. /* set up the directory for a search */
  524.     dirh = &curproc->srchdir[i];
  525.     dirh->fc = dir;
  526.     dirh->index = 0;
  527.     dirh->flags = TOS_SEARCH;
  528.     r = (*dir.fs->opendir)(dirh, dirh->flags);
  529.     if (r != 0) {
  530.         DEBUG(("Fsfirst(%s): couldn't open directory (error %ld)",
  531.             path, r));
  532.         release_cookie(&dir);
  533.         return r;
  534.     }
  535.  
  536. /* mark the slot as in-use */
  537.     curproc->srchdta[i] = dta;
  538.  
  539. /* set up the DTA for Fsnext */
  540.     dta->index = i;
  541.     dta->magic = SVALID;
  542.     dta->dta_sattrib = attrib;
  543.  
  544. /* OK, now basically just do Fsnext, except that instead of ENMFIL we
  545.  * return EFILNF.
  546.  * NOTE: If we already have found a volume label from the search above,
  547.  * then we skip the f_snext and just return that.
  548.  */
  549.     if (havelabel)
  550.         return 0;
  551.  
  552.     r = f_snext();
  553.     if (r == ENMFIL) r = EFILNF;
  554.     if (r)
  555.         TRACE(("Fsfirst: returning %ld", r));
  556. /* release_cookie isn't necessary, since &dir is now stored in the
  557.  * DIRH structure and will be released when the search is completed
  558.  */
  559.     return r;
  560. }
  561.  
  562. /*
  563.  * Counter for Fsfirst/Fsnext, so that we know which search slots are
  564.  * least recently used. This is updated once per second by the code
  565.  * in timeout.c.
  566.  * BUG: 1/second is pretty low granularity
  567.  */
  568.  
  569. long searchtime;
  570.  
  571. long ARGS_ON_STACK
  572. f_snext()
  573. {
  574.     char buf[TOS_NAMELEN+1];
  575.     DTABUF *dta = curproc->dta;
  576.     FILESYS *fs;
  577.     fcookie fc;
  578.     int i;
  579.     DIR *dirh;
  580.     long r;
  581.     XATTR xattr;
  582.  
  583.     TRACE(("Fsnext"));
  584.  
  585.     if (dta->magic == EVALID) {
  586.         DEBUG(("Fsnext: DTA marked a failing search"));
  587.         return ENMFIL;
  588.     }
  589.     if (dta->magic != SVALID) {
  590.         DEBUG(("Fsnext: dta incorrectly set up"));
  591.         return EINVFN;
  592.     }
  593.  
  594.     i = dta->index;
  595.     dirh = &curproc->srchdir[i];
  596.     curproc->srchtim[i] = searchtime;
  597.  
  598.     fs = dirh->fc.fs;
  599.     if (!fs)        /* oops -- the directory got closed somehow */
  600.         return EINTRN;
  601.  
  602. /* BUG: f_snext and readdir should check for disk media changes */
  603.  
  604.     for(;;) {
  605.         r = (*fs->readdir)(dirh, buf, TOS_NAMELEN+1, &fc);
  606.  
  607.         if (r == ENAMETOOLONG) {
  608.             DEBUG(("Fsnext: name too long"));
  609.             continue;    /* TOS programs never see these names */
  610.         }
  611.         if (r != 0) {
  612. baderror:
  613.             if (dirh->fc.fs)
  614.                 (void)(*fs->closedir)(dirh);
  615.             release_cookie(&dirh->fc);
  616.             dirh->fc.fs = 0;
  617.             curproc->srchdta[i] = 0;
  618.             dta->magic = EVALID;
  619.             if (r != ENMFIL)
  620.                 DEBUG(("Fsnext: returning %ld", r));
  621.             return r;
  622.         }
  623.  
  624.         if (!pat_match(buf, dta->dta_pat))
  625.         {
  626.             release_cookie(&fc);
  627.             continue;    /* different patterns */
  628.         }
  629.  
  630.     /* check for search attributes */
  631.         r = (*fc.fs->getxattr)(&fc, &xattr);
  632.         if (r) {
  633.             DEBUG(("Fsnext: couldn't get file attributes"));
  634.             release_cookie(&fc);
  635.             goto baderror;
  636.         }
  637.     /* if the file is a symbolic link, try to find what it's linked to */
  638.         if ( (xattr.mode & S_IFMT) == S_IFLNK ) {
  639.             char linkedto[PATH_MAX];
  640.             r = (*fc.fs->readlink)(&fc, linkedto, PATH_MAX);
  641.             release_cookie(&fc);
  642.             if (r == 0) {
  643.             /* the "1" tells relpath2cookie that we read a link */
  644.                 r = relpath2cookie(&dirh->fc, linkedto,
  645.                     follow_links, &fc, 1);
  646.                 if (r == 0) {
  647.                 r = (*fc.fs->getxattr)(&fc, &xattr);
  648.                 release_cookie(&fc);
  649.                 }
  650.             }
  651.             if (r) {
  652.                 DEBUG(("Fsnext: couldn't follow link: error %ld",
  653.                     r));
  654.             }
  655.         } else {
  656.             release_cookie(&fc);
  657.         }
  658.  
  659.     /* silly TOS rules for matching attributes */
  660.         if (xattr.attr == 0) break;
  661.         if (xattr.attr & 0x21) break;
  662.         if (dta->dta_sattrib & xattr.attr)
  663.             break;
  664.     }
  665.  
  666. /* here, we have a match */
  667.     dta->dta_attrib = xattr.attr;
  668.     dta->dta_time = xattr.mtime;
  669.     dta->dta_date = xattr.mdate;
  670.     dta->dta_size = xattr.size;
  671.     strcpy(dta->dta_name, buf);
  672.  
  673.     if (curproc->domain == DOM_TOS && !(fs->fsflags & FS_CASESENSITIVE)) {
  674.         strupr(dta->dta_name);
  675.     }
  676.     return 0;
  677. }
  678.  
  679. long ARGS_ON_STACK
  680. f_attrib(name, rwflag, attr)
  681.     const char *name;
  682.     int rwflag;
  683.     int attr;
  684. {
  685.     fcookie fc;
  686.     XATTR xattr;
  687.     long r;
  688.  
  689.     TRACE(("Fattrib(%s, %d)", name, attr));
  690.  
  691.     r = path2cookie(name, follow_links, &fc);
  692.  
  693.     if (r) {
  694.         DEBUG(("Fattrib(%s): error %ld", name, r));
  695.         return r;
  696.     }
  697.  
  698.     r = (*fc.fs->getxattr)(&fc, &xattr);
  699.  
  700.     if (r) {
  701.         DEBUG(("Fattrib(%s): getxattr returned %ld", name, r));
  702.         release_cookie(&fc);
  703.         return r;
  704.     }
  705.  
  706.     if (rwflag) {
  707.         if (attr & (FA_LABEL|FA_DIR)) {
  708.             DEBUG(("Fattrib(%s): illegal attributes specified",name));
  709.             r = EACCDN;
  710.         } else if (curproc->euid && curproc->euid != xattr.uid) {
  711.             DEBUG(("Fattrib(%s): not the file's owner",name));
  712.             r = EACCDN;
  713.         } else if (xattr.attr & (FA_LABEL|FA_DIR)) {
  714.             DEBUG(("Fattrib(%s): file is a volume label "
  715.                   "or directory",name));
  716.             r = EACCDN;
  717.         } else {
  718.             r = (*fc.fs->chattr)(&fc, attr);
  719.         }
  720.         release_cookie(&fc);
  721.         return r;
  722.     } else {
  723.         release_cookie(&fc);
  724.         return xattr.attr;
  725.     }
  726. }
  727.  
  728. long ARGS_ON_STACK
  729. f_delete(name)
  730.     const char *name;
  731. {
  732.     fcookie dir, fc;
  733.     long r;
  734.     char temp1[PATH_MAX];
  735.     XATTR    xattr;
  736.  
  737.     TRACE(("Fdelete(%s)", name));
  738.  
  739. /* get a cookie for the directory the file is in */
  740.     if (( r = path2cookie(name, temp1, &dir) ) != 0)
  741.     {
  742.         DEBUG(("Fdelete: couldn't get directory cookie: error %ld", r));
  743.         return r;
  744.     }
  745.  
  746. /* check for write permission on directory */
  747.     r = dir_access(&dir, S_IWOTH);
  748.     if (r) {
  749.         DEBUG(("Fdelete(%s): write access to directory denied",name));
  750.         release_cookie(&dir);
  751.         return EACCDN;
  752.     }
  753.  
  754. /* now get the file attributes */
  755. /* TOS domain processes can only delete files if they have write permission
  756.  * for them
  757.  */
  758.     if (curproc->domain == DOM_TOS) {
  759.         if ( (r = (*dir.fs->lookup)(&dir, temp1, &fc) ) != 0) {
  760.             DEBUG(("Fdelete: error %ld while looking for %s", r, temp1));
  761.             release_cookie(&dir);
  762.             return r;
  763.         }
  764.  
  765.         if (( r = (*fc.fs->getxattr)(&fc, &xattr)) < 0 )
  766.         {
  767.             release_cookie(&dir);
  768.             release_cookie(&fc);
  769.             DEBUG(("Fdelete: couldn't get file attributes: error %ld", r));
  770.             return r;
  771.         }
  772.     /* see if we're allowed to kill it */
  773.         if (denyaccess(&xattr, S_IWOTH)) {
  774.             release_cookie(&dir);
  775.             release_cookie(&fc);
  776.             DEBUG(("Fdelete: file access denied"));
  777.             return EACCDN;
  778.         }
  779.         release_cookie(&fc);
  780.     }
  781.  
  782.     r = (*dir.fs->remove)(&dir,temp1);
  783.  
  784.     release_cookie(&dir);
  785.     return r;
  786. }
  787.  
  788. long ARGS_ON_STACK
  789. f_rename(junk, old, new)
  790.     int junk;        /* ignored, for TOS compatibility */
  791.     const char *old, *new;
  792. {
  793.     fcookie olddir, newdir, oldfil;
  794.     XATTR xattr;
  795.     char temp1[PATH_MAX], temp2[PATH_MAX];
  796.     long r;
  797.  
  798.     UNUSED(junk);
  799.  
  800.     TRACE(("Frename(%s, %s)", old, new));
  801.  
  802.     r = path2cookie(old, temp2, &olddir);
  803.     if (r) {
  804.         DEBUG(("Frename(%s,%s): error parsing old name",old,new));
  805.         return r;
  806.     }
  807. /* check for permissions on the old file
  808.  * GEMDOS doesn't allow rename if the file is FA_RDONLY
  809.  * we enforce this restriction only on regular files; processes,
  810.  * directories, and character special files can be renamed at will
  811.  */
  812.     r = relpath2cookie(&olddir, temp2, (char *)0, &oldfil, 0);
  813.     if (r) {
  814.         DEBUG(("Frename(%s,%s): old file not found",old,new));
  815.         release_cookie(&olddir);
  816.         return r;
  817.     }
  818.     r = (*oldfil.fs->getxattr)(&oldfil, &xattr);
  819.     release_cookie(&oldfil);
  820.     if (r ||
  821.         ((xattr.mode & S_IFMT) == S_IFREG && (xattr.attr & FA_RDONLY)) )
  822.     {
  823.         DEBUG(("Frename(%s,%s): access to old file not granted",old,new));
  824.         release_cookie(&olddir);
  825.         return EACCDN;
  826.     }
  827.     r = path2cookie(new, temp1, &newdir);
  828.     if (r) {
  829.         DEBUG(("Frename(%s,%s): error parsing new name",old,new));
  830.         release_cookie(&olddir);
  831.         return r;
  832.     }
  833.  
  834.     if (newdir.fs != olddir.fs) {
  835.         DEBUG(("Frename(%s,%s): different file systems",old,new));
  836.         release_cookie(&olddir);
  837.         release_cookie(&newdir);
  838.         return EXDEV;    /* cross device rename */
  839.     }
  840.  
  841. /* check for write permission on both directories */
  842.     r = dir_access(&olddir, S_IWOTH);
  843.     if (!r) r = dir_access(&newdir, S_IWOTH);
  844.     if (r) {
  845.         DEBUG(("Frename(%s,%s): access to a directory denied",old,new));
  846.     } else {
  847.         r = (*newdir.fs->rename)(&olddir, temp2, &newdir, temp1);
  848.     }
  849.     release_cookie(&olddir);
  850.     release_cookie(&newdir);
  851.     return r;
  852. }
  853.  
  854. /*
  855.  * GEMDOS extension: Dpathconf(name, which)
  856.  * returns information about filesystem-imposed limits; "name" is the name
  857.  * of a file or directory about which the limit information is requested;
  858.  * "which" is the limit requested, as follows:
  859.  *    -1    max. value of "which" allowed
  860.  *    0    internal limit on open files, if any
  861.  *    1    max. number of links to a file    {LINK_MAX}
  862.  *    2    max. path name length        {PATH_MAX}
  863.  *    3    max. file name length        {NAME_MAX}
  864.  *    4    no. of bytes in atomic write to FIFO {PIPE_BUF}
  865.  *    5    file name truncation rules
  866.  *    6    file name case translation rules
  867.  *
  868.  * unlimited values are returned as 0x7fffffffL
  869.  *
  870.  * see also Sysconf() in dos.c
  871.  */
  872.  
  873. long ARGS_ON_STACK
  874. d_pathconf(name, which)
  875.     const char *name;
  876.     int which;
  877. {
  878.     fcookie dir;
  879.     long r;
  880.  
  881.     r = path2cookie(name, (char *)0, &dir);
  882.     if (r) {
  883.         DEBUG(("Dpathconf(%s): bad path",name));
  884.         return r;
  885.     }
  886.     r = (*dir.fs->pathconf)(&dir, which);
  887.     if (which == DP_CASE && r == EINVFN) {
  888.     /* backward compatibility with old .XFS files */
  889.         r = (dir.fs->fsflags & FS_CASESENSITIVE) ? DP_CASESENS :
  890.                 DP_CASEINSENS;
  891.     }
  892.     release_cookie(&dir);
  893.     return r;
  894. }
  895.  
  896. /*
  897.  * GEMDOS extension: Opendir/Readdir/Rewinddir/Closedir offer a new,
  898.  * POSIX-like alternative to Fsfirst/Fsnext, and as a bonus allow for
  899.  * arbitrary length file names
  900.  */
  901.  
  902. long ARGS_ON_STACK
  903. d_opendir(name, flag)
  904.     const char *name;
  905.     int flag;
  906. {
  907.     DIR *dirh;
  908.     fcookie dir;
  909.     long r;
  910.  
  911.     r = path2cookie(name, follow_links, &dir);
  912.     if (r) {
  913.         DEBUG(("Dopendir(%s): error %ld", name, r));
  914.         return r;
  915.     }
  916.     r = dir_access(&dir, S_IROTH);
  917.     if (r) {
  918.         DEBUG(("Dopendir(%s): read permission denied", name));
  919.         release_cookie(&dir);
  920.         return r;
  921.     }
  922.  
  923.     dirh = (DIR *)kmalloc(SIZEOF(DIR));
  924.     if (!dirh) {
  925.         release_cookie(&dir);
  926.         return ENSMEM;
  927.     }
  928.  
  929.     dirh->fc = dir;
  930.     dirh->index = 0;
  931.     dirh->flags = flag;
  932.     r = (*dir.fs->opendir)(dirh, flag);
  933.     if (r) {
  934.         DEBUG(("d_opendir(%s): opendir returned %ld", name, r));
  935.         release_cookie(&dir);
  936.         kfree(dirh);
  937.         return r;
  938.     }
  939.  
  940. /* we keep a chain of open directories so that if a process
  941.  * terminates without closing them all, we can clean up
  942.  */
  943.     dirh->next = curproc->searches;
  944.     curproc->searches = dirh;
  945.  
  946.     return (long)dirh;
  947. }
  948.  
  949. long ARGS_ON_STACK
  950. d_readdir(len, handle, buf)
  951.     int len;
  952.     long handle;
  953.     char *buf;
  954. {
  955.     DIR *dirh = (DIR *)handle;
  956.     fcookie fc;
  957.     long r;
  958.  
  959.     if (!dirh->fc.fs)
  960.         return EIHNDL;
  961.     r = (*dirh->fc.fs->readdir)(dirh, buf, len, &fc);
  962.     if (r == 0)
  963.         release_cookie(&fc);
  964.     return r;
  965. }
  966.  
  967. /* jr: just as d_readdir, but also returns XATTR structure (not
  968.    following links). Note that the return value reflects the
  969.    result of the Dreaddir operation, the result of the Fxattr
  970.    operation is stored in long *xret */
  971.  
  972. long ARGS_ON_STACK
  973. d_xreaddir(len, handle, buf, xattr, xret)
  974.     int len;
  975.     long handle;
  976.     char *buf;
  977.     XATTR *xattr;
  978.     long *xret;
  979. {
  980.     DIR *dirh = (DIR *)handle;
  981.     fcookie fc;
  982.     long r;
  983.  
  984.     if (!dirh->fc.fs) return EIHNDL;
  985.     r = (*dirh->fc.fs->readdir)(dirh, buf, len, &fc);
  986.     if (r != E_OK) return r;
  987.  
  988.     *xret = (*fc.fs->getxattr)(&fc, xattr);
  989.     
  990.     release_cookie(&fc);
  991.     return r;
  992. }
  993.  
  994.  
  995. long ARGS_ON_STACK
  996. d_rewind(handle)
  997.     long handle;
  998. {
  999.     DIR *dirh = (DIR *)handle;
  1000.  
  1001.     if (!dirh->fc.fs)
  1002.         return EIHNDL;
  1003.     return (*dirh->fc.fs->rewinddir)(dirh);
  1004. }
  1005.  
  1006. /*
  1007.  * NOTE: there is also code in terminate() in dosmem.c that
  1008.  * does automatic closes of directory searches.
  1009.  * If you change d_closedir(), you may also need to change
  1010.  * terminate().
  1011.  */
  1012.  
  1013. long ARGS_ON_STACK
  1014. d_closedir(handle)
  1015.     long handle;
  1016. {
  1017.     long r;
  1018.     DIR *dirh = (DIR *)handle;
  1019.     DIR **where;
  1020.  
  1021.     where = &curproc->searches;
  1022.     while (*where && *where != dirh) {
  1023.         where = &((*where)->next);
  1024.     }
  1025.     if (!*where) {
  1026.         DEBUG(("Dclosedir: not an open directory"));
  1027.         return EIHNDL;
  1028.     }
  1029.  
  1030. /* unlink the directory from the chain */
  1031.     *where = dirh->next;
  1032.  
  1033.     if (dirh->fc.fs) {
  1034.         r = (*dirh->fc.fs->closedir)(dirh);
  1035.         release_cookie(&dirh->fc);
  1036.     } else {
  1037.         r = 0;
  1038.     }
  1039.  
  1040.     if (r) {
  1041.         DEBUG(("Dclosedir: error %ld", r));
  1042.     }
  1043.     kfree(dirh);
  1044.     return r;
  1045. }
  1046.  
  1047. /*
  1048.  * GEMDOS extension: Fxattr gets extended attributes for a file. "flag"
  1049.  * is 0 if symbolic links are to be followed (like stat), 1 if not (like
  1050.  * lstat).
  1051.  */
  1052.  
  1053. long ARGS_ON_STACK
  1054. f_xattr(flag, name, xattr)
  1055.     int flag;
  1056.     const char *name;
  1057.     XATTR *xattr;
  1058. {
  1059.     fcookie fc;
  1060.     long r;
  1061.  
  1062.     TRACE(("Fxattr(%d, %s)", flag, name));
  1063.  
  1064.     r = path2cookie(name, flag ? (char *)0 : follow_links, &fc);
  1065.     if (r) {
  1066.         DEBUG(("Fxattr(%s): path2cookie returned %ld", name, r));
  1067.         return r;
  1068.     }
  1069.     r = (*fc.fs->getxattr)(&fc, xattr);
  1070.     if (r) {
  1071.         DEBUG(("Fxattr(%s): returning %ld", name, r));
  1072.     }
  1073.     release_cookie(&fc);
  1074.     return r;
  1075. }
  1076.  
  1077. /*
  1078.  * GEMDOS extension: Flink(old, new) creates a hard link named "new"
  1079.  * to the file "old".
  1080.  */
  1081.  
  1082. long ARGS_ON_STACK
  1083. f_link(old, new)
  1084.     const char *old, *new;
  1085. {
  1086.     fcookie olddir, newdir;
  1087.     char temp1[PATH_MAX], temp2[PATH_MAX];
  1088.     long r;
  1089.  
  1090.     TRACE(("Flink(%s, %s)", old, new));
  1091.  
  1092.     r = path2cookie(old, temp2, &olddir);
  1093.     if (r) {
  1094.         DEBUG(("Flink(%s,%s): error parsing old name",old,new));
  1095.         return r;
  1096.     }
  1097.     r = path2cookie(new, temp1, &newdir);
  1098.     if (r) {
  1099.         DEBUG(("Flink(%s,%s): error parsing new name",old,new));
  1100.         release_cookie(&olddir);
  1101.         return r;
  1102.     }
  1103.  
  1104.     if (newdir.fs != olddir.fs) {
  1105.         DEBUG(("Flink(%s,%s): different file systems",old,new));
  1106.         release_cookie(&olddir);
  1107.         release_cookie(&newdir);
  1108.         return EXDEV;    /* cross device link */
  1109.     }
  1110.  
  1111. /* check for write permission on the destination directory */
  1112.  
  1113.     r = dir_access(&newdir, S_IWOTH);
  1114.     if (r) {
  1115.         DEBUG(("Flink(%s,%s): access to directory denied",old,new));
  1116.     } else
  1117.         r = (*newdir.fs->hardlink)(&olddir, temp2, &newdir, temp1);
  1118.     release_cookie(&olddir);
  1119.     release_cookie(&newdir);
  1120.     return r;
  1121. }
  1122.  
  1123. /*
  1124.  * GEMDOS extension: Fsymlink(old, new): create a symbolic link named
  1125.  * "new" that contains the path "old".
  1126.  */
  1127.  
  1128. long ARGS_ON_STACK
  1129. f_symlink(old, new)
  1130.     const char *old, *new;
  1131. {
  1132.     fcookie newdir;
  1133.     long r;
  1134.     char temp1[PATH_MAX];
  1135.  
  1136.     TRACE(("Fsymlink(%s, %s)", old, new));
  1137.  
  1138.     r = path2cookie(new, temp1, &newdir);
  1139.     if (r) {
  1140.         DEBUG(("Fsymlink(%s,%s): error parsing %s", old,new,new));
  1141.         return r;
  1142.     }
  1143.     r = dir_access(&newdir, S_IWOTH);
  1144.     if (r) {
  1145.         DEBUG(("Fsymlink(%s,%s): access to directory denied",old,new));
  1146.     } else
  1147.         r = (*newdir.fs->symlink)(&newdir, temp1, old);
  1148.     release_cookie(&newdir);
  1149.     return r;
  1150. }
  1151.  
  1152. /*
  1153.  * GEMDOS extension: Freadlink(buflen, buf, linkfile):
  1154.  * read the contents of the symbolic link "linkfile" into the buffer
  1155.  * "buf", which has length "buflen".
  1156.  */
  1157.  
  1158. long ARGS_ON_STACK
  1159. f_readlink(buflen, buf, linkfile)
  1160.     int buflen;
  1161.     char *buf;
  1162.     const char *linkfile;
  1163. {
  1164.     fcookie file;
  1165.     long r;
  1166.     XATTR xattr;
  1167.  
  1168.     TRACE(("Freadlink(%s)", linkfile));
  1169.  
  1170.     r = path2cookie(linkfile, (char *)0, &file);
  1171.     if (r) {
  1172.         DEBUG(("Freadlink: unable to find %s", linkfile));
  1173.         return r;
  1174.     }
  1175.     r = (*file.fs->getxattr)(&file, &xattr);
  1176.     if (r) {
  1177.         DEBUG(("Freadlink: unable to get attributes for %s", linkfile));
  1178.     } else if ( (xattr.mode & S_IFMT) == S_IFLNK )
  1179.         r = (*file.fs->readlink)(&file, buf, buflen);
  1180.     else {
  1181.         DEBUG(("Freadlink: %s is not a link", linkfile));
  1182.         r = EACCDN;
  1183.     }
  1184.     release_cookie(&file);
  1185.     return r;
  1186. }
  1187.  
  1188. /*
  1189.  * GEMDOS extension: Dcntl(): do file system specific functions
  1190.  */
  1191.  
  1192. long ARGS_ON_STACK
  1193. d_cntl(cmd, name, arg)
  1194.     int cmd;
  1195.     const char *name;
  1196.     long arg;
  1197. {
  1198.     fcookie dir;
  1199.     long r;
  1200.     char temp1[PATH_MAX];
  1201.  
  1202.     TRACE(("Dcntl(cmd=%x, file=%s, arg=%lx)", cmd, name, arg));
  1203.  
  1204.     r = path2cookie(name, temp1, &dir);
  1205.     if (r) {
  1206.         DEBUG(("Dcntl: couldn't find %s", name));
  1207.         return r;
  1208.     }
  1209.     r = (*dir.fs->fscntl)(&dir, temp1, cmd, arg);
  1210.     release_cookie(&dir);
  1211.     return r;
  1212. }
  1213.  
  1214. /*
  1215.  * GEMDOS extension: Fchown(name, uid, gid) changes the user and group
  1216.  * ownerships of a file to "uid" and "gid" respectively.
  1217.  */
  1218.  
  1219. long ARGS_ON_STACK
  1220. f_chown(name, uid, gid)
  1221.     const char *name;
  1222.     int uid, gid;
  1223. {
  1224.     fcookie fc;
  1225.     XATTR xattr;
  1226.     long r;
  1227.  
  1228.     TRACE(("Fchown(%s, %d, %d)", name, uid, gid));
  1229.  
  1230.     r = path2cookie(name, NULL, &fc);
  1231.     if (r) {
  1232.         DEBUG(("Fchown(%s): error %ld", name, r));
  1233.         return r;
  1234.     }
  1235.  
  1236. /* MiNT acts like _POSIX_CHOWN_RESTRICTED: a non-privileged process can
  1237.  * only change the ownership of a file that is owned by this user, to
  1238.  * the effective group id of the process
  1239.  */
  1240.     if (curproc->euid) {
  1241.         if (curproc->egid != gid)
  1242.             r = EACCDN;
  1243.         else
  1244.             r = (*fc.fs->getxattr)(&fc, &xattr);
  1245.         if (r) {
  1246.             DEBUG(("Fchown(%s): unable to get file attributes",name));
  1247.             release_cookie(&fc);
  1248.             return r;
  1249.         }
  1250.         if (xattr.uid != curproc->euid || xattr.uid != uid) {
  1251.             DEBUG(("Fchown(%s): not the file's owner",name));
  1252.             release_cookie(&fc);
  1253.             return EACCDN;
  1254.         }
  1255.     }
  1256.     r = (*fc.fs->chown)(&fc, uid, gid);
  1257.     release_cookie(&fc);
  1258.     return r;
  1259. }
  1260.  
  1261. /*
  1262.  * GEMDOS extension: Fchmod(file, mode) changes a file's access
  1263.  * permissions.
  1264.  */
  1265.  
  1266. long ARGS_ON_STACK
  1267. f_chmod(name, mode)
  1268.     const char *name;
  1269.     unsigned mode;
  1270. {
  1271.     fcookie fc;
  1272.     long r;
  1273.     XATTR xattr;
  1274.  
  1275.     TRACE(("Fchmod(%s, %o)", name, mode));
  1276.     r = path2cookie(name, follow_links, &fc);
  1277.     if (r) {
  1278.         DEBUG(("Fchmod(%s): error %ld", name, r));
  1279.         return r;
  1280.     }
  1281.     r = (*fc.fs->getxattr)(&fc, &xattr);
  1282.     if (r) {
  1283.         DEBUG(("Fchmod(%s): couldn't get file attributes",name));
  1284.     }
  1285.     else if (curproc->euid && curproc->euid != xattr.uid) {
  1286.         DEBUG(("Fchmod(%s): not the file's owner",name));
  1287.         r = EACCDN;
  1288.     } else {
  1289.         r = (*fc.fs->chmode)(&fc, mode & ~S_IFMT);
  1290.         if (r) DEBUG(("Fchmod: error %ld", r));
  1291.     }
  1292.     release_cookie(&fc);
  1293.     return r;
  1294. }
  1295.  
  1296. /*
  1297.  * GEMDOS extension: Dlock(mode, dev): locks or unlocks access to
  1298.  * a BIOS device. "mode" bit 0 is 0 for unlock, 1 for lock; "dev" is a
  1299.  * BIOS device (0 for A:, 1 for B:, etc.).
  1300.  *
  1301.  * Returns: 0 if the operation was successful
  1302.  *          EACCDN if a lock attempt is made on a drive that is being
  1303.  *            used
  1304.  *        ELOCKED if the drive is locked by another process
  1305.  *        ENSLOCK if a program attempts to unlock a drive it
  1306.  *            hasn't locked.
  1307.  * ++jr: if mode bit 1 is set, then instead of returning ELOCKED the
  1308.  * pid of the process which has locked the drive is returned (unless
  1309.  * it was locked by pid 0, in which case ELOCKED is still returned).
  1310.  */
  1311.  
  1312. PROC *dlockproc[NUM_DRIVES];
  1313.  
  1314. long ARGS_ON_STACK
  1315. d_lock(mode, dev)
  1316.     int mode, dev;
  1317. {
  1318.     PROC *p;
  1319.     FILEPTR *f;
  1320.     int i;
  1321.  
  1322.     TRACE(("Dlock(%x,%c:)", mode, dev+'A'));
  1323.     if (dev < 0 || dev >= NUM_DRIVES) return EDRIVE;
  1324.     if (aliasdrv[dev]) {
  1325.         dev = aliasdrv[dev] - 1;
  1326.         if (dev < 0 || dev >= NUM_DRIVES)
  1327.             return EDRIVE;
  1328.     }
  1329.     if ( (mode&1) == 0) {    /* unlock */
  1330.         if (dlockproc[dev] == curproc) {
  1331.             dlockproc[dev] = 0;
  1332.             changedrv(dev);
  1333.             return 0;
  1334.         }
  1335.         DEBUG(("Dlock: no such lock"));
  1336.         return ENSLOCK;
  1337.     }
  1338.  
  1339. /* code for locking */
  1340. /* is the drive already locked? */
  1341.     if (dlockproc[dev]) {
  1342.         DEBUG(("Dlock: drive already locked"));
  1343. #if 0
  1344.         if (dlockproc[dev] == curproc) return 0;
  1345. #endif
  1346.         if (dlockproc[dev]->pid == 0) return ELOCKED;
  1347.         return (mode & 2) ? dlockproc[dev]->pid : ELOCKED;
  1348.     }
  1349. /* see if the drive is in use */
  1350.     for (p = proclist; p; p = p->gl_next) {
  1351.         if (p->wait_q == ZOMBIE_Q || p->wait_q == TSR_Q)
  1352.             continue;
  1353.         for (i = MIN_HANDLE; i < MAX_OPEN; i++) {
  1354.             if ( ((f = p->handle[i]) != 0) && 
  1355.                  (f != (FILEPTR *)1) && (f->fc.dev == dev) ) {
  1356.         DEBUG(("Dlock: process %d has an open handle on the drive", p->pid));
  1357.                 if (p->pid == 0) return EACCDN;
  1358.                 return (mode & 2) ? p->pid : EACCDN;
  1359.             }
  1360.         }
  1361.     }
  1362.  
  1363. /* if we reach here, the drive is not in use */
  1364. /* we lock it by setting dlockproc and by setting all root and current
  1365.  * directories referring to the device to a null file system
  1366.  */
  1367.     for (p = proclist; p; p = p->gl_next) {
  1368.         for (i = 0; i < NUM_DRIVES; i++) {
  1369.             if (p->root[i].dev == dev) {
  1370.                 release_cookie(&p->root[i]);
  1371.                 p->root[i].fs = 0;
  1372.             }
  1373.             if (p->curdir[i].dev == dev) {
  1374.                 release_cookie(&p->curdir[i]);
  1375.                 p->curdir[i].fs = 0;
  1376.             }
  1377.         }
  1378.     }
  1379.  
  1380.     dlockproc[dev] = curproc;
  1381.     return 0;
  1382. }
  1383.  
  1384. /* jr: GEMDOS-extensions Dreadlabel() and Dwritelabel() */
  1385.  
  1386. long ARGS_ON_STACK
  1387. d_readlabel(name, label, namelen)
  1388.     const char *name;
  1389.     char *label;
  1390.     int namelen;
  1391. {
  1392.     fcookie dir;
  1393.     long r;
  1394.  
  1395.     r = path2cookie(name, (char *)0, &dir);
  1396.     if (r) {
  1397.         DEBUG(("Dreadlabel(%s): bad path",name));
  1398.         return r;
  1399.     }
  1400.     r = (*dir.fs->readlabel)(&dir, label, namelen);
  1401.  
  1402.     release_cookie(&dir);
  1403.     return r;
  1404. }
  1405.  
  1406. long ARGS_ON_STACK
  1407. d_writelabel(name, label)
  1408.     const char *name;
  1409.     const char *label;
  1410. {
  1411.     fcookie dir;
  1412.     long r;
  1413.  
  1414.     r = path2cookie(name, (char *)0, &dir);
  1415.     if (r) {
  1416.         DEBUG(("Dwritelabel(%s): bad path",name));
  1417.         return r;
  1418.     }
  1419.     r = (*dir.fs->writelabel)(&dir, label);
  1420.  
  1421.     release_cookie(&dir);
  1422.     return r;
  1423. }
  1424.